package constants

import (
	"jvm/instructions/base"
	"jvm/rtda"
	"jvm/rtda/heap"
)

func _ldc(jFrame *rtda.JFrame, index uint) {
	stack := jFrame.OperandStack()
	class := jFrame.Method().Class()
	c := class.ConstantPool().GetConstant(index)
	switch d := c.(type) {
	case int32:
		stack.PushInt(d)
	case float32:
		stack.PushFloat(d)
	case string:
		internedStr := heap.JString(class.Loader(), d)
		stack.PushRef(internedStr)
	case *heap.ClassRef:
		classObj := d.ResolvedClass().JClass()
		stack.PushRef(classObj)
	default:
		panic("unsupported constant type")
	}
}

type LDC struct {
	base.Index8Instruction
}

func (l *LDC) Execute(jFrame *rtda.JFrame) {
	_ldc(jFrame, l.Index)
}

type LDC_W struct {
	base.Index16Instruction
}

func (l *LDC_W) Execute(jFrame *rtda.JFrame) {
	_ldc(jFrame, l.Index)
}

type LDC2_W struct {
	base.Index16Instruction
}

func (l *LDC2_W) Execute(jFrame *rtda.JFrame) {
	stack := jFrame.OperandStack()
	cp := jFrame.Method().Class().ConstantPool()
	c := cp.GetConstant(l.Index)
	switch d := c.(type) {
	case int64:
		stack.PushLong(d)
	case float64:
		stack.PushDouble(d)
	//case string:
	//case *heap.ClassRef:
	default:
		panic("unsupported constant type")
	}
}
